import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { Color4, Position2 } from 'src/app/services/models';
import { WebGLService } from 'src/app/services/webgl.service';

@Component({
    selector: 'draw-point',
    templateUrl: './draw-point.component.html',
    styleUrls: ['./draw-point.component.scss']
})
export class DrawPointComponent implements OnInit, AfterViewInit, OnDestroy {
    // 版本一
    private vertexShaderSource = `
        void main () {
            gl_Position = vec4(0.0, 0.5, 0.0, 1.0);
            gl_PointSize = 10.0;
        } 
    `;
    private fragShaderSource = `
        void main () {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        }
    `
    
    // 版本二 使用 attribute 变量
    private vertexShaderSource2 = `
        attribute vec4 a_Position;
        attribute float a_PointSize;
        void main () {
            gl_Position = a_Position;
            gl_PointSize = a_PointSize;
        } 
    `;
    private fragShaderSource2 = `
        void main () {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        }
    `;

    // 版本三
    private fragShaderSource3 = `
        precision mediump float;
        uniform vec4 u_FragColor;
        void main () {
            gl_FragColor = u_FragColor;
        }
    `;

    private clickSubject = new Subject<MouseEvent>();
    private gl;
    constructor(private webglService: WebGLService) { }

    ngOnInit() {}

    ngAfterViewInit () {
        this.init1();
        this.init2();
        this.init3();
    }

    ngOnDestroy () {
        delete this.gl;
    }

    // 版本一
    init1 () {
        const canvas = document.querySelector('#myCanvas') as HTMLCanvasElement;
        this.gl = canvas.getContext('webgl');

        // 初始化 shader
        this.webglService.initShader(this.gl, this.vertexShaderSource, this.fragShaderSource);

        // 设置背景颜色
        this.gl.clearColor(0.0, 0.0, 0.0, 1.0);
        this.gl.clear(this.gl.COLOR_BUFFER_BIT);

        // 画点
        this.gl.drawArrays(this.gl.POINTS, 0, 1);
    }

    // 版本二
    init2 () {
        const canvas = document.querySelector('#myCanvas2') as HTMLCanvasElement;
        const gl = canvas.getContext('webgl');

        // 初始化 shader
        this.webglService.initShader(gl, this.vertexShaderSource2, this.fragShaderSource2);

        const program = this.webglService.getProgramByGLContext(gl);
        // 获取 attribute 变量 a_Position 的存储位置
        const aPosition = gl.getAttribLocation(program, 'a_Position');
        if (aPosition < 0) return console.error('获取 attribute 位置出错.');

        // 获取 attribute 变量 a_Position 的存储位置
        const aPointSize = gl.getAttribLocation(program, 'a_PointSize');
        if (aPointSize < 0) return console.error('获取 attribute 位置出错.');

        setInterval(() => {
            const x = Math.random() * 2 - 1;
            const y = Math.random() * 2 - 1;
            const fontSize = Math.random() * 10 + 5;
            // 将顶点位置传输给 attribute 变量
            gl.vertexAttrib3f(aPosition, x, y, 0.0);
            gl.vertexAttrib1f(aPointSize, fontSize);

            // 设置背景颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);

            // 画点
            gl.drawArrays(gl.POINTS, 0, 1);
        }, 500);
    }

    // 版本三
    init3 () {
        const canvas = document.querySelector('#myCanvas3') as HTMLCanvasElement;
        const gl = canvas.getContext('webgl');

        // 初始化 shader
        this.webglService.initShader(gl, this.vertexShaderSource2, this.fragShaderSource3);

        const program = this.webglService.getProgramByGLContext(gl);
        // 获取 attribute 变量 a_Position 的存储位置
        const aPosition = gl.getAttribLocation(program, 'a_Position');
        if (aPosition < 0) return console.error('获取 attribute 位置出错.');

        // 获取 attribute 变量 a_Position 的存储位置
        const aPointSize = gl.getAttribLocation(program, 'a_PointSize');
        if (aPointSize < 0) return console.error('获取 attribute 位置出错.');

        // 获取 uniform 变量 u_FragColor 的存储位置
        const uFragColor = gl.getUniformLocation(program, 'u_FragColor');
        if (uFragColor < 0) return console.error('获取 uniform 位置出错.');

        // 设置背景颜色
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        const points: Position2[] = [];
        
        this.clickSubject.subscribe(event => {
            const point = this.getRelativeXY(canvas, event);
            points.push(point);

            // 设置背景颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);

            points.forEach(p => {
                const { x, y } = p;
                // 将顶点位置传输给 attribute 变量
                gl.vertexAttrib3f(aPosition, x, y, 0.0);

                const fontSize = Math.random() * 10 + 5;
                gl.vertexAttrib1f(aPointSize, fontSize);

                const {r, g, b, a} = this.getColor(x, y);
                gl.uniform4f(uFragColor, r, g, b, a);

                // 画点
                gl.drawArrays(gl.POINTS, 0, 1);
            });
        });
    }

    onClick (e) {
        this.clickSubject.next(e);
    }

    getRelativeXY (dom: HTMLCanvasElement, event: MouseEvent): Position2 {
        const rect = dom.getBoundingClientRect();
        const mouseX = event.clientX;
        const mouseY = event.clientY;

        const x = ((mouseX - rect.left) - dom.width / 2) / (dom.width / 2);
        const y = (dom.height / 2 - (mouseY - rect.top)) / (dom.height / 2);
        
        return { x, y};
    }

    getColor (x: number, y: number): Color4 {
        if (x > 0 && y > 0) {
            return { r: 1.0, g: 0.0, b: 0.0, a: 1.0};
        } else if (x < 0 && y < 0) {
            return { r: 0.0, g: 1.0, b: 0.0, a: 1.0};
        } else {
            return { r: 1.0, g: 1.0, b: 1.0, a: 1.0};
        }
    }
}